package com.github.lh

import java.security.KeyPairGenerator
import java.security.PrivateKey
import java.security.PublicKey
import java.security.SecureRandom
import java.security.spec.AlgorithmParameterSpec
import java.security.spec.ECGenParameterSpec
import java.util.*


class Wallet(
        val name: String
) {

    val privateKey: PrivateKey
    val publicKey: PublicKey
    val UTXOs: HashMap<String, TransactionOutput> = hashMapOf()

    init {
        val (_privateKey, _publicKey) = genKey()
        privateKey = _privateKey
        publicKey = _publicKey
    }

    fun genKey(): Pair<PrivateKey, PublicKey> {
        val keyGen = KeyPairGenerator.getInstance("ECDSA", "BC")
        val random = SecureRandom.getInstance("SHA1PRNG")
        val ecSpec: AlgorithmParameterSpec = ECGenParameterSpec("prime192v1")
        // Initialize the key generator and generate a KeyPair
        keyGen.initialize(ecSpec, random) //256
        val keyPair = keyGen.generateKeyPair()
        // Set the public and private keys from the keyPair
        return keyPair.private to keyPair.public
    }



    fun getBalance(): Float =
            Chain.UTXOs.values.filter { it.isMine(publicKey) }
                    .onEach { UTXOs[it.id] = it }
                    .map { it.value }
                    .let {
                        if (it.isEmpty()) 0f
                        else it.reduce { a, b -> a + b }
                    }


    fun sendFunds(receiver: PublicKey, value: Float): Transaction? {
        if (getBalance() < value) {
            println("#Not Enough funds to send transaction. Transaction Discarded.")
            return null
        }
        val inputs = ArrayList<TransactionInput>()

        var total = 0f
        for (item in UTXOs.entries) {
            val UTXO = item.value
            total += UTXO.value
            inputs.add(TransactionInput(UTXO.id))
            if (total > value) break
        }

        val newTransaction = Transaction(publicKey, receiver, value, inputs)
        newTransaction.generateSignature(privateKey)

        for (input in inputs) {
            UTXOs.remove(input.transactionOutputId)
        }

        return newTransaction
    }

    fun printBalance() {
        println("$name`s Balance: ${getBalance()}")
    }
}